import { ElMessage } from 'element-plus'

function sleep(time: number) {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve(undefined)
    }, time)
  })
}

type SpeechTasks = Array<() => Promise<number>>

export default class Speech {
  private tasks: SpeechTasks = []
  private isSpeaking = false
  private interval = 1000
  private voiceList!: SpeechSynthesisVoice[]
  private voice!: SpeechSynthesisVoice
  constructor(interval = 1000) {
    if (Speech.isSupported()) {
      speechSynthesis.onvoiceschanged = this.getVoice.bind(this)
      this.interval = interval
    }
    else {
      console.warn('该浏览器不支持 speechSynthesis API')
      ElMessage.warning('该浏览器不支持语音播报功能')
    }
  }

  static isSupported() {
    return typeof window.speechSynthesis !== 'undefined'
  }

  private getVoice() {
    // 使用本地中文语音
    this.voiceList = speechSynthesis.getVoices().filter(voice => voice.lang === 'zh-CN' && voice.localService)
    this.voice = this.voiceList[this.voiceList.length - 1]
  }

  // 生成一个speaking任务
  private getSpeaker(text: string) {
    const voice = this.voice
    return function (): Promise<number> {
      return new Promise((resolve) => {
        const speaker = new SpeechSynthesisUtterance(text)
        speaker.voice = voice
        speechSynthesis.speak(speaker)
        speaker.onend = function (e) {
          resolve(e.elapsedTime)
        }
      })
    }
  }

  // 递归取出队头任务并执行
  private async runNext(tasks: SpeechTasks) {
    if (tasks.length > 0) {
      const task = tasks.shift()
      task && await task()
      await sleep(this.interval)
      this.runNext(tasks)
    }
  }

  async speak(text: string, repeatCount = 0) {
    if (!text || !Speech.isSupported()) {
      return
    }
    // 将播报任务加入队列中
    for (let i = 0; i <= repeatCount; i++) {
      const sp = this.getSpeaker(text)
      this.tasks.push(sp)
    }
    if (this.isSpeaking) {
      return
    }
    // 空闲状态开始执行任务
    this.isSpeaking = true
    await this.runNext(this.tasks)
    this.isSpeaking = false
  }
}
